home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 February: Tool Chest / Apple Developer CD Series Tool Chest February 1996 (Apple Computer)(1996).iso / Sample Code / SCSI Samples 1.0 / SCSI Inquiry Samples ƒ / SCSI Inquiry (Asynch) 06⁄07 ƒ / Src / SCSIInquiry.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-16  |  10.6 KB  |  342 lines  |  [TEXT/KAHL]

  1. #define ASYNCHRONOUS
  2. /*                                SCSIInquiry.c                            */
  3. /*
  4.  * SCSIInquiry.c
  5.  * Copyright © 1994 Apple Computer Inc. All rights reserved.
  6.  * This is a minimal sample to illustrate the Asynchronous SCSI Manager.
  7.  *
  8.  * Note: this program will crash if the asynchronous SCSI Manager is
  9.  * not installed. SCSI Simple Sample shows how to test for the presence
  10.  * of the asynchronous SCSI Manager.
  11.  */
  12. #include "SCSIInquiry.h"
  13.  
  14. #ifndef THINK_C                /* MPW includes            */
  15. #include <Errors.h>
  16. #include <Script.h>
  17. #include <Types.h>
  18. #include <Files.h>
  19. #include <Resources.h>
  20. #include <QuickDraw.h>
  21. #include <Fonts.h>
  22. #include <Events.h>
  23. #include <Windows.h>
  24. #include <ToolUtils.h>
  25. #include <Memory.h>
  26. #include <Menus.h>
  27. #include <Lists.h>
  28. #include <Printing.h>
  29. #include <Dialogs.h>
  30. #include <StandardFile.h>
  31. #include <Packages.h>
  32. #endif
  33.  
  34. /*
  35.  * Include the O.S. files in a specific order to make sure that we have
  36.  * a definition for the _SCSIAtomic trap.
  37.  */
  38. #include <Traps.h>
  39. #ifndef _SCSIAtomic
  40. #define _SCSIAtomic    0xA089
  41. #endif
  42. /*
  43.  * As of this writing, the Asynchronous SCSI Manager definitions have
  44.  * not been added to the standard header distribution. This include
  45.  * references a working version that is stored in the application
  46.  * folder hierarchy.
  47.  */
  48. #include "SCSI.h"
  49.  
  50. DeviceIdent                gTargetDevice = { 0, 0, 0, 0 };    /* Target ID 0    */
  51.  
  52. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  53.  * SCSI Definitions
  54.  */
  55. #define    kScsiCmdInquiry            0x12        /* Device inquiry command    */
  56.  
  57. struct SCSI_6_Byte_Command {                /* Six-byte command            */
  58.     unsigned char        opcode;                /*  0                        */
  59.     unsigned char        lbn3;                /*  1 lbn in low 5            */
  60.     unsigned char        lbn2;                /*  2                        */
  61.     unsigned char        lbn1;                /*  3                        */
  62.     unsigned char        len;                /*  4                        */
  63.     unsigned char        ctrl;                /*  5                        */
  64. };
  65. typedef struct SCSI_6_Byte_Command SCSI_6_Byte_Command;
  66.  
  67. struct SCSI_Inquiry_Data {                    /* Inquiry returns this        */
  68.     unsigned char        devType;            /*  0 Device type,            */
  69.     unsigned char        devTypeMod;            /*  1 Device type modifier    */
  70.     unsigned char        version;            /*  2 ISO/ECMA/ANSI version    */
  71.     unsigned char        format;                /*  3 Response data format    */
  72.     unsigned char        length;                /*  4 Additional Length        */
  73.     unsigned char        reserved5;            /*  5 Reserved                */
  74.     unsigned char        reserved6;            /*  6 Reserved                */
  75.     unsigned char        flags;                /*  7 Capability flags        */
  76.     unsigned char        vendor[8];            /*  8-15 Vendor-specific    */
  77.     unsigned char        product[16];        /* 16-31 Product id            */
  78.     unsigned char        revision[4];        /* 32-35 Product revision    */
  79.     unsigned char        vendorSpecific[20]; /* 36-55 Vendor stuff        */
  80.     unsigned char        moreReserved[40];    /* 56-95 Reserved            */
  81. };
  82. typedef struct SCSI_Inquiry_Data SCSI_Inquiry_Data;
  83.  
  84. SCSI_Inquiry_Data            gInquiryData;    /* Inquiry data goes here    */
  85. unsigned long                gInquirySize;    /* Number of bytes read        */
  86.  
  87. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  88.  * gSCSICommand is the command that we send to the device.
  89.  */
  90. SCSI_6_Byte_Command            gSCSICommand = {
  91.         kScsiCmdInquiry,                    /* Command                    */
  92.         0,                                    /* LBN 3 -- unused            */
  93.         0,                                    /* LBN 2 -- unused            */
  94.         0,                                    /* LBN 1 -- unused            */
  95.         sizeof (SCSI_Inquiry_Data),            /* Returned buffer length    */
  96.         0                                    /* Flags -- must be zero    */
  97.     };
  98.  
  99. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  100.  * The SCSIBusInquiry command returns the number of bytes in the parameter
  101.  * block. We then allocate a block of the correct size. Note that the
  102.  * block is cleared to zero when it is allocated.
  103.  */
  104. SCSIBusInquiryPB            gSCSIBusInquiryPB;
  105. SCSIExecIOPB                *gSCSIExecIOPB;
  106. unsigned long                gSCSIExecIOPBSize;
  107. Boolean                        gSCSICommandComplete;
  108. #define kCompletionTimeout    (250)                /* 250 Msec total time    */
  109.  
  110. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  111.  * Local functions and administrative variables.
  112.  */
  113.  
  114. #ifdef __powerc
  115. QDGlobals                qd;
  116. #endif
  117.  
  118. void                        DisplayError(
  119.         OSErr                    errorStatus,
  120.         ConstStr255Param        errorMessage
  121.     );
  122. OSErr                        DoSCSICommand(
  123.         unsigned short            targetID,
  124.         const Ptr                scsiCommand,
  125.         SCSIInstr                *requestTIB
  126.     );
  127. void                        DisplaySCSIInquiry(
  128.         long                    actualTransferCount
  129.     );
  130. pascal void                    MySCSICallbackProc(
  131.         void                    *ioPtr
  132.     );
  133. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  134.  * Local functions and administrative variables.
  135.  */
  136. void
  137. main(void)
  138. {
  139.         short                    i;
  140.         OSErr                    status;
  141.         EventRecord                eventRecord;
  142.         long                    actualTransferCount;
  143.             
  144.         MaxApplZone();        
  145.         InitGraf(&qd.thePort);
  146.         InitFonts();
  147.         InitWindows();
  148.         InitMenus();
  149.         TEInit();
  150.         InitDialogs(0);
  151.         for (i = 0; i < 3; i++)
  152.             EventAvail(everyEvent, &eventRecord);
  153.         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  154.          * Call the SCSIBusInquiry command to determine the length of the
  155.          * command block for the actual transfer.
  156.          */
  157.         gSCSIBusInquiryPB.scsiPBLength = sizeof gSCSIBusInquiryPB;
  158.         gSCSIBusInquiryPB.scsiFunctionCode = SCSIBusInquiry;
  159.         gSCSIBusInquiryPB.scsiDevice = gTargetDevice;
  160.         SCSIAction((SCSI_PB *) &gSCSIBusInquiryPB);
  161.         status = gSCSIBusInquiryPB.scsiResult;
  162.         if (status != noErr) {
  163.             DisplayError(status, "\pSCSIBusInquiry failed");
  164.             ExitToShell();
  165.         }
  166.         gSCSIExecIOPBSize = gSCSIBusInquiryPB.scsiIOpbSize;
  167.         gSCSIExecIOPB = (SCSIExecIOPB *) NewPtrClear(gSCSIExecIOPBSize);
  168.         if (gSCSIExecIOPB == NULL) {
  169.             DisplayError(MemError(), "\pNo memory for param. block");
  170.             ExitToShell();
  171.         }
  172.         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  173.          * Setup the parameter block for the user's request.
  174.          */
  175.         gSCSIExecIOPB->scsiPBLength = gSCSIExecIOPBSize;
  176.         gSCSIExecIOPB->scsiFunctionCode = SCSIExecIO;
  177.         gSCSIExecIOPB->scsiTimeout = kCompletionTimeout;
  178.         gSCSIExecIOPB->scsiDevice = gTargetDevice;
  179.         /*
  180.          * Copy the command block into the SCSI ExecIO Parameter block to
  181.          * centralize everything for debugging.
  182.          */
  183.         BlockMove(
  184.             &gSCSICommand,
  185.             &gSCSIExecIOPB->scsiCDB,
  186.             sizeof gSCSICommand
  187.         );
  188.         gSCSIExecIOPB->scsiCDBLength = sizeof gSCSICommand;
  189.         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  190.          * Specify the transfer direction, if any, and set the other SCSI
  191.          * operation flags. scsiSIMQNoFreeze prevents the SCSI Manager from
  192.          * blocking further operation if an error is detected.
  193.          */
  194.         gSCSIExecIOPB->scsiFlags =
  195.                     scsiSIMQNoFreeze            /* Don't stop on errors    */
  196.                     | scsiDirectionIn            /* We're reading        */
  197.                     | scsiDisableAutosense        /* No Request Sense        */
  198.                     | scsiDontDisconnect;        /* No disconnect        */
  199.         gSCSIExecIOPB->scsiDataPtr = (unsigned char *) &gInquiryData;
  200.         gSCSIExecIOPB->scsiDataLength = sizeof gInquiryData;
  201.         gSCSIExecIOPB->scsiDataType = scsiDataBuffer;
  202.         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  203.          * For polled transfers, turn off select with attention so
  204.          * the device doesn't disconnect. This is inefficient, but
  205.          * is useful for the Device Identity, Mode Sense, and
  206.          * some other administrative commands.
  207.          */
  208.         gSCSIExecIOPB->scsiHandshake[0] = 0;    /* Not used for polled    */
  209.         gSCSIExecIOPB->scsiIOFlags |= scsiDisableSelectWAtn;
  210.         gSCSIExecIOPB->scsiTransferType = scsiTransferPolled;
  211.         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  212.          * Now, call the SCSI Command manager
  213.          */
  214. #ifdef ASYNCHRONOUS
  215.         gSCSIExecIOPB->scsiCompletion = MySCSICallbackProc;
  216.         gSCSICommandComplete = false;
  217. #else
  218.         gSCSIExecIOPB->scsiCompletion = NULL;    /* Synchronous            */
  219. #endif
  220.         status = SCSIAction((SCSI_PB *) gSCSIExecIOPB);
  221. #ifdef ASYNCHRONOUS
  222.         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  223.          * In application that take advantage of the asynchronous SCSI
  224.          * Manager, the mainline code would handle user interaction and
  225.          * display management, while all SCSI and file I/O would be carried
  226.          * out by I/O completion routines. This is a dummy event loop
  227.          * that waits until the SCSIAction call completes by calling
  228.          * MySCSICallbackProc. Note that we do not wait if the original
  229.          * call to SCSIAction failed, presumably because of a bad
  230.          * parameter.
  231.          *
  232.          * Note: if your application calls the SCSI Manager asynchronously
  233.          * and SCSIAction returns noErr, your code MUST NOT examine any
  234.          * field within the SCSI parameter block, or any memory that it
  235.          * references until your completion routine has been called. Thus,
  236.          * this sample DOES NOT examine gSCSIExecIOPB->scsiResult until
  237.          * the global "completion flag" has been set.
  238.          */
  239.         if (status == noErr) {
  240.             while (status == noErr && gSCSICommandComplete == false)
  241.                 EventAvail(everyEvent, &eventRecord);
  242.             status = gSCSIExecIOPB->scsiResult;
  243.         }
  244. #endif
  245.         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  246.          * If the device returned less data than we requested, the SCSI
  247.          * Manager will return an error status. We check that we actually
  248.          * received some data and cancel the error if this is the case.
  249.          */
  250.         actualTransferCount = gSCSIExecIOPB->scsiDataLength
  251.                     - gSCSIExecIOPB->scsiDataResidual;
  252.         if (status == scsiDataRunError && actualTransferCount > 0)
  253.             status = noErr;
  254.         if (status != noErr)
  255.             DisplayError(status, "\pSCSIAction");
  256.         else {
  257.             DisplaySCSIInquiry(actualTransferCount);
  258.         }
  259.         ExitToShell();
  260. }
  261.  
  262. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  263.  * This completion routine is called by the SCSI Manager when the
  264.  * SCSIAction procedure completes.
  265.  */
  266. pascal void
  267. MySCSICallbackProc(
  268.         void                    *ioPtr
  269.     )
  270. {
  271.         gSCSICommandComplete = true;
  272. }
  273.  
  274. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  275.  * Display the inquiry result.
  276.  */
  277. static void
  278. StoreString(
  279.         const unsigned char        *textPtr,
  280.         Size                    textLength,
  281.         StringPtr                result
  282.     )
  283. {
  284.         register short            i;
  285.         
  286.         for (i = textLength; i > 0; --i) {
  287.             if (textPtr[i - 1] != ' ' && textPtr[i - 1] != 0)
  288.                 break;
  289.         }
  290.         BlockMove(textPtr, &result[1], i);
  291.         result[0] = i;
  292. }
  293.  
  294. void
  295. DisplaySCSIInquiry(
  296.         long                    actualTransferCount
  297.     )
  298. {
  299.         Str255                    inquirySize;
  300.         Str255                    vendorName;
  301.         Str255                    productName;
  302.         Str255                    revisionLevel;
  303.         
  304.         NumToString(actualTransferCount, inquirySize);
  305.         StoreString(
  306.             gInquiryData.vendor,
  307.             sizeof gInquiryData.vendor,
  308.             vendorName
  309.         );
  310.         StoreString(
  311.             gInquiryData.product,
  312.             sizeof gInquiryData.product,
  313.             productName
  314.         );
  315.         StoreString(
  316.             gInquiryData.revision,
  317.             sizeof gInquiryData.revision,
  318.             revisionLevel
  319.         );
  320.         ParamText(inquirySize, vendorName, productName, revisionLevel);
  321.         NoteAlert(ALRT_Info, NULL);
  322. }
  323.  
  324.  
  325. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  326.  * Display an error alert.
  327.  */
  328. void
  329. DisplayError(
  330.         OSErr                    errorStatus,
  331.         ConstStr255Param        errorMessage
  332.     )
  333. {
  334.         Str255                    work;
  335.         
  336.         NumToString(errorStatus, work);
  337.         ParamText(work, errorMessage, "\p", "\p");
  338.         InitCursor();
  339.         StopAlert(ALRT_Error, NULL);
  340. }
  341.  
  342.